/*
 * Copyright (c) 2007 Aleksey Nikiforov
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * * Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright
 *   notice, this list of conditions and the following disclaimer in the
 *   documentation and/or other materials provided with the distribution.
 *
 * * Neither the name of 'Aleksey Nikiforov' nor the names of other contributors 
 *   may be used to endorse or promote products derived from this software 
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.lex.input.effects.filter;


import org.lex.input.effects.component.AccelComponent;
import org.lex.input.effects.component.AccelConfig;

import com.jme.math.FastMath;

public class AccelFilter2d extends AccelConfig implements InputFilter2d {

	private AccelComponent positiveX;
	private AccelComponent negativeX;
	private AccelComponent positiveY;
	private AccelComponent negativeY;
	
	private float inputX;
	private float inputY;
	
	private float speedX;
	private float speedY;
	
	private float travelX;
	private float travelY;
	
	public AccelFilter2d(float mass,
					   float force,
					   float damping,
					   float maxSpeed)
	{
		super(mass, force, damping, maxSpeed);
		
		positiveX = new AccelComponent(this);
		negativeX = new AccelComponent(this);
		positiveY = new AccelComponent(this);
		negativeY = new AccelComponent(this);
	}
	
	public float getOutputX() {
		return travelX;
	}
	
	public float getOutputY() {
		return travelY;
	}
	
	public void feedInputX(float input) {
		inputX += input;
	}
	
	public void feedInputY(float input) {
		inputY += input;
	}
	
	public void update(float deltaT) {
		if (inputX > 0) positiveX.applyForce();
		else if (inputX < 0) negativeX.applyForce();
		inputX = 0;
		
		if (inputY > 0) positiveY.applyForce();
		else if (inputY < 0) negativeY.applyForce();
		inputY = 0;
		
		positiveX.update(deltaT);
		negativeX.update(deltaT);
		positiveY.update(deltaT);
		negativeY.update(deltaT);
		
		float newSpeedX = positiveX.getSpeed() - negativeX.getSpeed();
		float newSpeedY = positiveY.getSpeed() - negativeY.getSpeed();
		
		// svl: speed vector length
		float svl = FastMath.sqrt(newSpeedX*newSpeedX + newSpeedY*newSpeedY);
		if (svl > maxSpeed) {
			float correction = maxSpeed/svl;
			
			positiveX.scaleSpeed(correction);
			negativeX.scaleSpeed(correction);
			positiveY.scaleSpeed(correction);
			negativeY.scaleSpeed(correction);
			
			newSpeedX *= correction;
			newSpeedY *= correction;
		} else if (svl < SPEED_CUTOFF) {
			newSpeedX = 0;
			newSpeedY = 0;
		}
		
		travelX = (speedX + newSpeedX)*deltaT/2;
		travelY = (speedY + newSpeedY)*deltaT/2;
		
		speedX = newSpeedX;
		speedY = newSpeedY;
	}

	public void clear() {
		positiveX.clear();
		negativeX.clear();
		speedX = 0;
		
		positiveY.clear();
		negativeY.clear();
		speedY = 0;
	}
	
}
